package jbeagle.concurrent.client;

import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

import org.apache.log4j.Logger;

import jbeagle.concurrent.remote.ConcurrentEvaluationManager;
import jbeagle.core.FitnessFunction;


public class RemoteEvaluatorLoader {
	
	static Logger log = Logger.getLogger(RemoteEvaluatorLoader.class);
	
	private static String hostName, rmiServerName, evalName;
	private static int port;
	
	protected ConcurrentEvaluationManager evalMgr;
	
	public static void main(String args[]) {
		checkArgs(args);
		RemoteEvaluatorLoader loader = new RemoteEvaluatorLoader();
		loader.setRemoteManager(hostName, rmiServerName, port);
		loader.loadAndRun(evalName);
	}
	
	public static void checkArgs(String args[]) {
		if ( args.length < 2 ) {
			log.error("Insufficient args, provide at least hostname and rmi name");
			System.exit(1);
		}
		
		if ( args[0] == null || args[0].isEmpty() || args[1] == null || args[1].isEmpty() ) {
			log.error("Insufficient args, provide at least hostname and rmi name");
			System.exit(1);
		}
		
		hostName = args[0];
		rmiServerName = args[1];
		port = (args.length < 3 || args[2] == null || args[2].isEmpty() ? 0 : Integer.parseInt(args[2]));
		evalName = (args.length < 4 || args[3] == null ? "unnamed" : args[3]);
	}

	public void setRemoteManager( ConcurrentEvaluationManager mgr ) {
		evalMgr = mgr;
	}
	
	public void setRemoteManager(String host, String rmiName, int port) {
		if (System.getSecurityManager() == null) {
            System.setSecurityManager(new SecurityManager());
        }
    	Registry registry;
        try {
	    	if ( port <= 0 )
	        	registry = LocateRegistry.getRegistry(host);
	        else
	        	registry = LocateRegistry.getRegistry(host, port);
	    	evalMgr = (ConcurrentEvaluationManager) registry.lookup(rmiName);
        } catch (RemoteException re) {
			log.error("Cannot use RMI server with name " + rmiName + " on host " + host + ":" + port + ":\n" + re);
		} catch (NotBoundException be) {
			log.error("RMI server with name " + rmiName + " on host " + host + ":" + port + " isn't bound.");
		}
	}

	public void loadAndRun(String evalName) {
		FitnessFunction ff = loadFitnessFunction();
		if ( ff == null ) {
			log.error("Could not load fitness function. Not running.");
			return;
		}
		
		Evaluator eval = new Evaluator(ff, evalName);
		eval.setEvaluationManager(evalMgr);
		eval.run();
	}
	
	protected FitnessFunction loadFitnessFunction() {
		Class<? extends FitnessFunction> fitnessClass = null;
		try {
			fitnessClass = evalMgr.getFitnessFunctionDef();
		} catch (RemoteException re) {
			log.error("Problem when trying to obtain fitness function class: " + re);
			return null;
		} catch (NullPointerException ne) {
			log.error("An evaluation manager needs to be set before running the evaluator.");
			return null;
		}
		
		FitnessFunction ff = null;
		try {
			ff = fitnessClass.newInstance();
		} catch (InstantiationException e) {
			log.error("Could not instantiate fitness function class " + fitnessClass + " : " + e);
		} catch (IllegalAccessException e) {
			log.error("Could not obtain access to fitness function class " + fitnessClass + " : " + e);
		}
		return ff;
	}
	
}
